import { flexRender } from '@tanstack/react-table';
import cx from 'classnames';
import React, { useContext, useMemo } from 'react';
import Tooltip from '../../../Tooltip';
import { getColumnPinningStyle } from '../../utils';
import { useDraggableRow } from '../../utils/useDraggable';

import type { Row } from '@tanstack/react-table';
import type { Context } from '../../context/table';
import type {
  AnyObject,
  ColumnMeta,
  ColumnPinning,
  ColumnPinningInfo,
  Size,
  TableOnCell,
  TableOnRow,
} from '../../type';

export interface Props<T extends AnyObject, Context = any> {
  context: React.Context<Context>;
  isShowBoxShadow?: boolean;
  bordered?: boolean;
  size?: Size;
  prefixCls?: string;
  isCanDrag?: boolean;
  isCanResizeColumn?: boolean;
  row: Row<T>;
  columnPinning: ColumnPinning;
  columnPinningInfo: ColumnPinningInfo;
  reorderRow: (draggedRowIndex: number, targetRowIndex: number) => void;
  onRow?: TableOnRow<T>;
  onCell?: TableOnCell<T>;
}

function TableRow<T extends AnyObject>(props: Props<T>) {
  const {
    prefixCls,
    row,
    reorderRow,
    isShowBoxShadow,
    isCanDrag,
    bordered,
    columnPinning,
    columnPinningInfo,
    size,
    context,
  } = props;
  const { dropRef, dragRef, previewRef, isDragging } = useDraggableRow({
    row,
    reorderRow,
  });
  const {
    table: { isCanEdit, errors, curOperateInfo },
  } = useContext<Context<T>>(context);

  const trProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {
      // key: row.id,
    };
    if (isCanDrag) {
      props.style = {
        opacity: isDragging ? 0.5 : 1,
        cursor: isDragging ? 'move' : 'default',
      };
      props.ref = previewRef;
    }
    return props;
  }, [isCanDrag, isDragging, previewRef, row]);
  const trBoxProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {};
    if (isCanDrag) {
      props.ref = dropRef;
    }
    return props;
  }, [isCanDrag, dropRef]);
  const trContentProps = useMemo(() => {
    const props: React.DetailedHTMLProps<
      React.HTMLAttributes<HTMLDivElement>,
      HTMLDivElement
    > = {};
    if (isCanDrag) {
      props.ref = dragRef;
    }
    return props;
  }, [isCanDrag, dragRef]);

  const {
    onClick: onClickRow,
    onDoubleClick: onDoubleClickRow,
    onMouseEnter: onMouseEnterRow,
    onMouseLeave: onMouseLeaveRow,
  } = (props.onRow && props.onRow(row.original, row.index)) || {};
  const {
    onClick: onClickCell,
    onDoubleClick: onDoubleClickCell,
    onMouseEnter: onMouseEnterCell,
    onMouseLeave: onMouseLeaveCell,
  } = (props.onCell && props.onCell(row.original, row.index)) || {};

  return (
    <div role="row" className={`${prefixCls}-tr`} {...trProps} key={row.id}>
      <div className={`${prefixCls}-tr-box`} {...trBoxProps}>
        <div
          className={`${prefixCls}-tr-content`}
          {...trContentProps}
          onClick={onClickRow}
          onDoubleClick={onDoubleClickRow}
          onMouseEnter={onMouseEnterRow}
          onMouseLeave={onMouseLeaveRow}
        >
          {row.getVisibleCells().map((cell) => {
            const { column } = cell;
            const columnMeta = (column.columnDef.meta as ColumnMeta<T>) || {};
            const { align, className, ellipsis, editType } = columnMeta;

            const style: React.CSSProperties = {
              ...getColumnPinningStyle(
                column.id,
                columnPinningInfo,
                columnPinning,
                isShowBoxShadow,
              ),
              width: isNaN(column.getSize()) ? 'auto' : column.getSize(),
            };

            const isSetOnCell = !editType;
            const cellProps: React.DetailedHTMLProps<
              React.HTMLAttributes<HTMLDivElement>,
              HTMLDivElement
            > = { style };
            if (isSetOnCell) {
              cellProps.onClick =
                onClickCell && onClickCell.bind(this, column.id);
              cellProps.onDoubleClick =
                onDoubleClickCell && onDoubleClickCell.bind(this, column.id);
              cellProps.onMouseEnter =
                onMouseEnterCell && onMouseEnterCell.bind(this, column.id);
              cellProps.onMouseLeave =
                onMouseLeaveCell && onMouseLeaveCell.bind(this, column.id);
            }
            const error = errors[row.index] && errors[row.index][column.id];
            return (
              <div
                {...cellProps}
                role="cell"
                className={cx(`${prefixCls}-td`, { bordered, className }, size)}
                key={cell.id}
                onClick={(e) => {
                  row.index === curOperateInfo.rowIndex &&
                    column.id === curOperateInfo.columnId &&
                    e.stopPropagation();
                }}
              >
                {ellipsis && (!isCanEdit || !editType) ? (
                  <Tooltip
                    title={flexRender(column.columnDef.cell, cell.getContext())}
                  >
                    <div
                      className={cx(`${prefixCls}-td-element`, align, {
                        ellipsis,
                      })}
                    >
                      {flexRender(column.columnDef.cell, cell.getContext())}
                    </div>
                  </Tooltip>
                ) : (
                  <div className={cx(`${prefixCls}-td-element`, align)}>
                    {flexRender(column.columnDef.cell, cell.getContext())}
                  </div>
                )}

                {isCanEdit && !!(error && error.length) && (
                  <Tooltip title={error[0].message} color="red">
                    <div className={`${prefixCls}-td-error`}></div>
                  </Tooltip>
                )}
              </div>
            );
          })}
        </div>
      </div>
    </div>
  );
}
export default TableRow;
